﻿/*
Copyright (C) 2012 Laurent Tardif (laurent.tardif@persistentsas.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;

namespace org.codeplex.TestUtils
{
    /// <summary>
    /// Helper class to launch powershell scripts
    /// </summary>
    public class ShellUtils
    {
        private static void ReadStreamHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            // Collect the sort command output.
            if (!String.IsNullOrEmpty(outLine.Data))
            {
                // Add the text to the collected output.
                Console.WriteLine("OUT  :" + outLine.Data.ToString());
                Console.Error.WriteLine("OUT  :" + outLine.Data.ToString());
            }
        }
        private static void ReadErrorStreamHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            // Collect the sort command output.
            if (!String.IsNullOrEmpty(outLine.Data))
            {
                // Add the text to the collected output.
                Console.WriteLine("ERROR :" + outLine.Data.ToString());
                Console.Error.WriteLine("ERROR :" + outLine.Data.ToString());
            }
        }

        /// <summary>
        /// Execute a script powershell with parameter inside a sub process running powershell
        /// </summary>
        /// <param name="scriptName"></param>
        /// <param name="additionalParameters"></param>
        /// <param name="timeoutInMillis"></param>
        /// <returns></returns>
        public static int ExecutePowershellScript32(string scriptName, string additionalParameters, int timeoutInMillis)
        {
            string power32=@"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
            if (! File.Exists(power32))
            {
                power32 = "powershell.exe";
            }
            return ExecutePowershellScriptCommon(power32, scriptName, additionalParameters, timeoutInMillis);    
        }

        /// <summary>
        /// Execute a script powershell with parameter inside a sub process running powershell
        /// </summary>
        /// <param name="scriptName"></param>
        /// <param name="additionalParameters"></param>
        /// <param name="timeoutInMillis"></param>
        /// <returns></returns>
        public static int ExecutePowershellScript(string scriptName, string additionalParameters, int timeoutInMillis)
        {
            return ExecutePowershellScriptCommon("powershell.exe", scriptName, additionalParameters, timeoutInMillis);
        }

        /// <summary>
        /// Execute a script powershell with parameter inside a sub process running powershell
        /// </summary>
        /// <param name="powershell"></param>
        /// <param name="scriptName"></param>
        /// <param name="additionalParameters"></param>
        /// <param name="timeoutInMillis"></param>
        /// <returns></returns>
        public static int ExecutePowershellScriptCommon(string powershell, string scriptName, string additionalParameters, int timeoutInMillis)
        {
            string processParameters = string.Empty;
            string scriptFullPath = Path.Combine(Directory.GetCurrentDirectory(), scriptName);
            string fileParameter = " -file \"" + scriptFullPath + "\" ";
            processParameters = fileParameter + additionalParameters + processParameters;
            //var startInfo = new ProcessStartInfo("powershell.exe", processParameters) { UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true };
            //http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput.aspx


            Process process = new Process();

            //intialise shell parameters
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.RedirectStandardOutput = true;
            //block script execution in PS if set to yes ...
			//process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.CreateNoWindow = true;



            //initialise command
            process.StartInfo.FileName = powershell;
            process.StartInfo.Arguments = processParameters;

            process.OutputDataReceived += new DataReceivedEventHandler(ReadStreamHandler);
            process.ErrorDataReceived += new DataReceivedEventHandler(ReadErrorStreamHandler);

            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            bool success = process.WaitForExit(timeoutInMillis);
            if (!success) throw new Exception("powershell did not exit in time");

            int ExitCode = process.ExitCode;

            if (ExitCode > 0 & !process.HasExited)
            {
                process.Kill();
            }

            //now clean up after ourselves
            process.Dispose();
            return ExitCode;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="MSDosArguments"></param>
        /// <returns></returns>
        public bool ExecuteMSDosCommand(string command, string MSDosArguments)
        {
            Process MSDosProcess = new Process();
            ProcessStartInfo MSDOSStartInfo = new ProcessStartInfo();

            MSDOSStartInfo.FileName = "CMD.exe ";

            //do not write error output to standard stream
            MSDOSStartInfo.RedirectStandardError = false;
            //do not write output to Process.StandardOutput Stream
            MSDOSStartInfo.RedirectStandardOutput = false;
            //do not read input from Process.StandardInput (i/e; the keyboard)
            MSDOSStartInfo.RedirectStandardInput = false;

            MSDOSStartInfo.UseShellExecute = false;
            //Dont show a command window
            MSDOSStartInfo.CreateNoWindow = true;

            MSDOSStartInfo.Arguments = "/D /c " + command +" "+ MSDosArguments;

            MSDosProcess.EnableRaisingEvents = true;
            MSDosProcess.StartInfo = MSDOSStartInfo;

            //start cmd.exe & the XCOPY process
            MSDosProcess.Start();

            //set the wait period for exiting the process
            MSDosProcess.WaitForExit(15000); //or the wait time you want

            int ExitCode = MSDosProcess.ExitCode;
            bool XCopySuccessful = true;

            //Now we need to see if the process was successful
            if (ExitCode > 0 & !MSDosProcess.HasExited)
            {
                MSDosProcess.Kill();
                XCopySuccessful = false;
            }

            //now clean up after ourselves
            MSDosProcess.Dispose();
            MSDOSStartInfo = null;
            return XCopySuccessful;
        }


    }
}
